#ifndef ESTATISTICA_CPP
#define ESTATISTICA_CPP

#include "individuo.cpp"
#include <vector>
#include <fstream>
#include<math.h>

#define INTERVALODECONFIANCA95 1.96

class Estatistica {
private:
	vector<Individuo> individuos;
	double primeiroMomentoW1;
	double primeiroMomentoW2;
	double primeiroMomentoX1;
	double primeiroMomentoX2;
	double primeiroMomentoT1;
	double primeiroMomentoT2;
	double varianciaW1;
	double varianciaW2;
	double varianciaTempoServico1;
	double varianciaTempoServico2;
	double varianciaTempoTotal1;
	double varianciaTempoTotal2;
	double primeiroMomentoW;
	double primeiroMomentoX;
	double primeiroMomentoT;
	double intervaloDeConfiancaTempoEspera1;
	double intervaloDeConfiancaTempoEspera2;
	double intervaloDeConfiancaTempoServico1;
	double intervaloDeConfiancaTempoServico2;
	double intervaloDeConfiancaTempoTotal1;
	double intervaloDeConfiancaTempoTotal2;
	double tempoInicioEvento1;
	double tempoFimEvento1;
	double tempoInicioEvento2;
	double tempoFimEvento2;
	double primeiroMomentoNq1;
	double primeiroMomentoN1;
	double primeiroMomentoNq2;
	double primeiroMomentoN2;
	double inicioRodada;
	int apagueme;
	double somatorioN1;
	double somatorioN2;
	double somatorioW1;
	double somatorioW2;
	double somatorioX1;
	double somatorioX2;
	double somatorioT1;
	double somatorioT2;
	double icW1;
	double icW2;
	double icN1;
	double icN2;
	double icT1;
	double icT2;



public:
	Estatistica() {
		apagueme = 0;
        primeiroMomentoW1 = 0;
        primeiroMomentoW2 = 0;
	    primeiroMomentoX1 = 0;
	    primeiroMomentoX2 = 0;
	    primeiroMomentoT1 = 0;
	    primeiroMomentoT2 = 0;
	    varianciaW1 = 0;
	    varianciaW2 = 0;
		primeiroMomentoW = 0;
		primeiroMomentoX = 0;
		primeiroMomentoT = 0;
		tempoInicioEvento1 = 0;
		tempoInicioEvento2 = 0;
		primeiroMomentoNq1=0;
		primeiroMomentoN1=0;
		primeiroMomentoNq2=0;
		primeiroMomentoN2=0;
		somatorioN1 = 0;
		somatorioN2 = 0;
		somatorioW1 = 0;
		somatorioW2 = 0;
		somatorioX1 = 0;
		somatorioN2 = 0;
		somatorioT1 = 0;
		somatorioT2 = 0;



		 ofstream myfile;
		 myfile.open ("n1.txt");
		 myfile.close();
		 myfile.open ("n2.txt");
		 myfile.close();
		 myfile.open ("w1.txt");
		 myfile.close();
		 myfile.open ("w2.txt");
		 myfile.close();
		 myfile.open ("t1.txt");
		 myfile.close();
		 myfile.open ("t2.txt");
		 myfile.close();

	}
	void setInicioRodada(double tempo){
		inicioRodada = tempo;
	}

	void reset()
	{
		primeiroMomentoN1 = 0;
		primeiroMomentoN2 = 0;
		primeiroMomentoNq1 = 0;
		primeiroMomentoNq2 = 0;
		primeiroMomentoW1 = 0;
		primeiroMomentoW2 = 0;
		primeiroMomentoW = 0;
		primeiroMomentoT1 = 0;
		primeiroMomentoT2 = 0;
		primeiroMomentoT = 0;
		primeiroMomentoX1 = 0;
		primeiroMomentoX2 = 0;
		primeiroMomentoX = 0;
	}


	void salvarEstatisticas(double const &tempoAtual)
	{

		calcPrimeiroMomentoX1();
		calcPrimeiroMomentoX2();
		calcPrimeiroMomentoW1();
		calcPrimeiroMomentoW2();
		calcPrimeiroMomentoT1(tempoAtual);
		calcPrimeiroMomentoT2(tempoAtual);
		salvarPrimeiroMomentoN1(tempoAtual);
		salvarPrimeiroMomentoN2(tempoAtual);
		salvarPrimeiroMomentoW1(tempoAtual);
		salvarPrimeiroMomentoW2(tempoAtual);
		salvarPrimeiroMomentoT1(tempoAtual);
		salvarPrimeiroMomentoT2(tempoAtual);


	}
	void salvarPrimeiroMomentoN1(double const &tempoAtual)
	{
		 ofstream myfile;
		 somatorioN1 += primeiroMomentoN1;
		 primeiroMomentoN1 = somatorioN1;
		// primeiroMomentoN1 /= (tempoAtual - inicioRodada);
		 primeiroMomentoNq1 /= (tempoAtual - inicioRodada);
		 primeiroMomentoN1 /= (tempoAtual - 0);
		 //primeiroMomentoNq1 /= (tempoAtual - 0);
		 myfile.open ("n1.txt", ios::app);
		 myfile << ++apagueme*200 <<" "<< primeiroMomentoN1  << "\n";
		 myfile.close();

	}

	void

	void salvarPrimeiroMomentoN2(double const &tempoAtual)
	{
		 ofstream myfile;
		 somatorioN2 += primeiroMomentoN2;
		 primeiroMomentoN2 = somatorioN2;
		 //primeiroMomentoN2 /= (tempoAtual - inicioRodada);
		 primeiroMomentoN2 /= (tempoAtual - 0);
		 primeiroMomentoNq2 /= (tempoAtual - inicioRodada);
		 myfile.open ("n2.txt", ios::app);
		 myfile << apagueme*200 << " "<< primeiroMomentoN2 << "\n";
		 myfile.close();
	}

	void salvarPrimeiroMomentoT1(double const &tempoAtual)
	{
		 ofstream myfile;
		 myfile.open ("t1.txt", ios::app);
		 myfile <<  apagueme*200 << " "<< primeiroMomentoT1 << "\n";
		 myfile.close();
	}

	void salvarPrimeiroMomentoT2(double const &tempoAtual)
	{
		 ofstream myfile;
		 myfile.open ("t2.txt", ios::app);
		 myfile <<   apagueme*200 << " "<<primeiroMomentoT2 << "\n";
		 myfile.close();
	}

	void salvarPrimeiroMomentoW1(double const &tempoAtual)
	{
		ofstream myfile;
		myfile.open ("w1.txt", ios::app);
		myfile << apagueme*200 << " "<<primeiroMomentoW1 << "\n";
		myfile.close();

	}
	void salvarPrimeiroMomentoW2(double const &tempoAtual)
	{
		ofstream myfile;
		myfile.open ("w2.txt", ios::app);
		myfile <<  apagueme*200 << " "<<primeiroMomentoW2 << "\n";
		myfile.close();

	}

	void calcPrimeiroMomentoT1(double tempoAtual)
	{
		//somatorioT1 += somatorioW1 + somatorioX1;
		primeiroMomentoT1 = primeiroMomentoW1 + primeiroMomentoX1;
		//primeiroMomentoT1 = primeiroMomentoT1/tempoAtual;
		//primeiroMomentoT1 = primeiroMomentoW1 + primeiroMomentoX1;
	}

	void calcPrimeiroMomentoT2(double tempoAtual)
	{
		//somatorioT2 += somatorioW2 + somatorioX2;
		primeiroMomentoT2 = primeiroMomentoW2 + primeiroMomentoX2;
		//primeiroMomentoT2 = primeiroMomentoT2/tempoAtual;
		//primeiroMomentoT2 = primeiroMomentoW2 + primeiroMomentoX2;
	}

	void calcPrimeiroMomentoX1()
	{
		primeiroMomentoX1 = 0;
		for(int i= 0; i< (int) individuos.size(); i++)
		{
			primeiroMomentoX1 += individuos[i].getX1();
		}
		somatorioX1 += primeiroMomentoX1;
		primeiroMomentoX1 = somatorioX1;
		primeiroMomentoX1 /= (int) individuos.size() * (apagueme+1);
		//primeiroMomentoX1/= (int) individuos.size();
	}

	void calcPrimeiroMomentoX2()
	{
		for(int i= 0; i<(int) individuos.size(); i++)
		{
			primeiroMomentoX2 += individuos[i].getX2();
		}
		somatorioX2 += primeiroMomentoX2;
		primeiroMomentoX2 = somatorioX2;
		primeiroMomentoX2 /= (int) individuos.size()*(apagueme+1);

		//primeiroMomentoX2/= (int) individuos.size();
	}



	void setTempoFimEvento1(double const &tempo)
	{
		tempoFimEvento1 = tempo;
	}
	void setTempoFimEvento2(double const &tempo)
	{
		tempoFimEvento2 = tempo;
	}

	void atualizaPrimeiroMometoN1(int nq1, int n1)
	{

		this->primeiroMomentoNq1 += (tempoFimEvento1 - tempoInicioEvento1)*nq1;
		this->primeiroMomentoN1 += (tempoFimEvento1 - tempoInicioEvento1)*n1;
		tempoInicioEvento1 = tempoFimEvento1;
	}

	void atualizaPrimeiroMomentoN2(int nq2, int n2)
	{

		this->primeiroMomentoNq2 += (tempoFimEvento2 - tempoInicioEvento2)*nq2;
		this->primeiroMomentoN2 += (tempoFimEvento2 - tempoInicioEvento2)*n2;
		tempoInicioEvento2 = tempoFimEvento2;
	}

	int getQuantidadeIndividuosAtendidos()
	{
		return individuos.size();
	}

	void armazenaEstatistica(Individuo i)
	{
        i.setW1();
        i.setW2();
        i.setT1();
        i.setT2();
		i.setW();
		i.setX();
		i.setT();
		individuos.push_back(i);
	}
	
	//calcula E[W1]
	void calcPrimeiroMomentoW1()
	{
		primeiroMomentoW1 = 0;
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMomentoW1 += individuos[i].getW1();
		}
		somatorioW1 += primeiroMomentoW1;
		primeiroMomentoW1 = somatorioW1;
		primeiroMomentoW1 /= (int)individuos.size()*(apagueme+1);
		//primeiroMomentoW1 =  primeiroMomentoW1 / individuos.size();
	}
	

	//calcula E[W2]
	void calcPrimeiroMomentoW2()
	{
		primeiroMomentoW2 = 0;
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMomentoW2 += individuos[i].getW2();
		}
		somatorioW2 += primeiroMomentoW2;
		primeiroMomentoW2 = somatorioW2;
		primeiroMomentoW2 /=(int)individuos.size()*(apagueme+1);
		//primeiroMomentoW2 = primeiroMomentoW2 / individuos.size();
	}
	

	void calcIcW1()
	{

	}
	void calcVarianciaW1()
	{

		for (int i = 0; i < (int) individuos.size(); i++) {
            varianciaW1 += (individuos[i].getW1() - primeiroMomentoW1)*(individuos[i].getW1() - primeiroMomentoW1);// verificar notacao
		}
		varianciaW1 = varianciaW1 / (int) individuos.size();
	}


	void calcVarianciaW2()
	{
		for (int i = 0; i < (int) individuos.size(); i++) {
            varianciaW2 = (individuos[i].getW2() - primeiroMomentoW2)*(individuos[i].getW2() - primeiroMomentoW2);
		}
		varianciaW2 = varianciaW2 / (int) individuos.size();
	}
	
	double getPrimeiroMomentoX1()
	{
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMomentoX1 += individuos[i].getX1(); // verificar notacao
		}
		return primeiroMomentoX1 / individuos.size();
	}
	
	double getPrimeiroMomentoX2()
	{
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMomentoX2 += individuos[i].getX2(); // verificar notacao
		}
		return primeiroMomentoX2 / individuos.size();
	}
	
	/*
	double getTempoServico1AoQuadradoMedio()
	{
		double tempoServico1AoQuadradoMedio = 0;
		double tempoServico1 = 0;
        
		for (int i = 0; i < (int) individuos.size(); i++) {
            tempoServico1 = individuos[i].getX1();
			tempoServico1AoQuadradoMedio += tempoServico1 * tempoServico1; // verificar notacao
		}
		return tempoServico1AoQuadradoMedio / individuos.size();
	}
	
	double getTempoServico2AoQuadradoMedio() {
		double tempoServico2AoQuadradoMedio = 0;
		double tempoServico2 = 0;
        
		for (int i = 0; i < (int) individuos.size(); i++) {
            tempoServico2 = individuos[i].getX2();
			tempoServico2AoQuadradoMedio += tempoServico2 * tempoServico2; // verificar notacao
		}
		return tempoServico2AoQuadradoMedio / individuos.size();
	}
	

	//calcula E[T1]
	double getPrimeiroMomentoT1() {
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMometoT1 += individuos[i].getT1(); // verificar notacao
		}
		return primeiroMometoT1 / individuos.size();
	}
	
	//calcula E[T2]
	double getTempoTotal2Medio() {
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMometoT2 += individuos[i].getT2(); // verificar notacao
		}
		return primeiroMometoT2 / individuos.size();
	}
	

   //calcula E[T1^2]
	double getTempoTotal1AoQuadradoMedio() {
		double tempoTotal1AoQuadradoMedio = 0;
		double tempoTotal1 = 0;
        
		for (int i = 0; i < (int) individuos.size(); i++) {
            tempoTotal1 = individuos[i].getT1();
			tempoTotal1AoQuadradoMedio += tempoTotal1 * tempoTotal1; // verificar notacao
		}
		return tempoTotal1AoQuadradoMedio / individuos.size();
   }
	
	//calcula E[T2^2]
	double getTempoTotal2AoQuadradoMedio() {
		double tempoTotal2AoQuadradoMedio = 0;
		double tempoTotal2 = 0;
        
		for (int i = 0; i < (int) individuos.size(); i++) {
            tempoTotal2 = individuos[i].getT2();
			tempoTotal2AoQuadradoMedio += tempoTotal2 * tempoTotal2; // verificar notacao
		}
		return tempoTotal2AoQuadradoMedio / individuos.size();
   }

	//calcula V(W1)
	void setVarianciaTempoEspera1()
	{
          varianciaW1 = getTempoEsperaFila1AoQuadradoMedio() - 
                                  getPrimeiroMomentoW1()*getPrimeiroMomentoW1();
    }
    
    float getVarianciaTempoEspera1()
    {
          return varianciaW1;
    }
    
    //calcula V(W2)
    void setVarianciaTempoEspera2()
	{
          varianciaW2 = getTempoEsperaFila2AoQuadradoMedio() -
                                  getPrimeiroMomentoW2()*getPrimeiroMomentoW2();
    }
    
    float getVarianciaTempoEspera2()
    {
          return varianciaW2;
    }
    
    void setVarianciaTempoServico1()
	{
          varianciaTempoServico1 = getTempoServico1AoQuadradoMedio() - 
                                  getPrimeiroMomentoX1() * getPrimeiroMomentoX1();
    }
    
    float getVarianciaTempoServico1()
    {
          return varianciaTempoServico1;
    }
    
    void setVarianciaTempoServico2()
	{
          varianciaTempoServico2 = getTempoServico2AoQuadradoMedio() - 
                                  getPrimeiroMomentoX2() * getPrimeiroMomentoX2();
    }
    
    double getVarianciaTempoServico2()
    {
          return varianciaTempoServico2;
    }
    
    //calcula V(T1)
    void setVarianciaTempoTotal1()
    {
         varianciaTempoTotal1 = getTempoTotal1AoQuadradoMedio() -
                                getPrimeiroMomentoT1() * getPrimeiroMomentoT1();
    }
    
    double getVarianciaTempoTotal1()
    {
          return varianciaTempoTotal1;
    }
    
    //calcula V(T2)
    void setVarianciaTempoTotal2()
    {
         varianciaTempoTotal2 = getTempoTotal2AoQuadradoMedio() -
                                getTempoTotal2Medio() * getTempoTotal2Medio();
    }
    
    double getVarianciaTempoTotal2()
    {
          return varianciaTempoTotal2;
    }
    
    double getTempoEsperaMedio() {
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMometoW += individuos[i].getW(); // verificar notacao
		}
		return primeiroMometoW / individuos.size();
	}
	
    double getTempoServicoMedio() {
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMometoX += individuos[i].getX(); // verificar notacao
		}
		return primeiroMometoX / individuos.size();
	}
	
    double getTempoTotalMedio() {
		for (int i = 0; i < (int) individuos.size(); i++) {
			primeiroMometoT += individuos[i].getT(); // verificar notacao
		}
		return primeiroMometoT / individuos.size();
	}
	
	//define o intervalo de confianca para W1
	void setIntervaloDeConfiancaTempoEspera1(int numeroDeRodadas)
	{
          setVarianciaTempoEspera1();
          varianciaW1 /= numeroDeRodadas - 1;
          
          intervaloDeConfiancaTempoEspera1 = INTERVALODECONFIANCA95 * 
                                             (sqrt(varianciaW1)/sqrt(numeroDeRodadas));
    }
    
	double getIntervaloDeConfiancaTempoEspera1()
    {
          return intervaloDeConfiancaTempoEspera1;
    }
    
    //verifica se um valor esta no intervalo de confianca de W1
    bool intervaloTempoEspera1(double valor)
    {
         if((valor>getPrimeiroMomentoW1()-getIntervaloDeConfiancaTempoEspera1())&&
            (valor<getPrimeiroMomentoW1()+getIntervaloDeConfiancaTempoEspera1()))
         {
             return true;
         }
         else
         {
             return false;
         }
    }
    
    //define o intervalo de confianca para W2
    void setIntervaloDeConfiancaTempoEspera2(int numeroDeRodadas)
	{
          setVarianciaTempoEspera2();
          varianciaW2 /= numeroDeRodadas - 1;
          
          intervaloDeConfiancaTempoEspera2 = INTERVALODECONFIANCA95 * 
                                             (sqrt(varianciaW2)/sqrt(numeroDeRodadas));
    }
    
    double getIntervaloDeConfiancaTempoEspera2()
    {
          return intervaloDeConfiancaTempoEspera2;
    }
    
    //verifica se um valor esta no intervalo de confianca de W2
    bool intervaloTempoEspera2(double valor)
    {
         if((valor>getPrimeiroMomentoW1()-getIntervaloDeConfiancaTempoEspera2())&&
            (valor<getPrimeiroMomentoW1()+getIntervaloDeConfiancaTempoEspera2()))
         {
             return true;
         }
         else
         {
             return false;
         }
    }
    
    void setIntervaloDeConfiancaTempoServico1(int numeroDeRodadas)
	{
          setVarianciaTempoServico1();
          varianciaTempoServico1 /= numeroDeRodadas - 1;
          
          intervaloDeConfiancaTempoServico1 = INTERVALODECONFIANCA95 * 
                                             (sqrt(varianciaTempoServico1)/sqrt(numeroDeRodadas));
    }
    
    double getIntervaloDeConfiancaTempoServico1()
    {
          return intervaloDeConfiancaTempoServico1;
    }
    
    bool intervaloTempoServico1(double valor)
    {
         if((valor>getPrimeiroMomentoX1()-getIntervaloDeConfiancaTempoServico1())&&
            (valor<getPrimeiroMomentoX1()+getIntervaloDeConfiancaTempoServico1()))
         {
             return true;
         }
         else
         {
             return false;
         }
    }
    
    void setIntervaloDeConfiancaTempoServico2(int numeroDeRodadas)
	{
          setVarianciaTempoServico2();
          varianciaTempoServico2 /= numeroDeRodadas - 1;
          
          intervaloDeConfiancaTempoServico2 = INTERVALODECONFIANCA95 * 
                                             (sqrt(varianciaTempoServico2)/sqrt(numeroDeRodadas));
    }
    
    double getIntervaloDeConfiancaTempoServico2()
    {
          return intervaloDeConfiancaTempoServico2;
    }
    
    bool intervaloTempoServico2(double valor)
    {
         if((valor>getPrimeiroMomentoX2()-getIntervaloDeConfiancaTempoServico2())&&
            (valor<getPrimeiroMomentoX2()+getIntervaloDeConfiancaTempoServico2()))
         {
             return true;
         }
         else
         {
             return false;
         }
    }
    
    //define o intervalo de confianca para T1
    void setIntervaloDeConfiancaTempoTotal1(int numeroDeRodadas)
	{
          setVarianciaTempoTotal1();
          varianciaTempoTotal1 /= numeroDeRodadas - 1;
          
          intervaloDeConfiancaTempoTotal1 = INTERVALODECONFIANCA95 * 
                                             (sqrt(varianciaTempoTotal1)/sqrt(numeroDeRodadas));
    }
    
    double getIntervaloDeConfiancaTempoTotal1()
    {
          return intervaloDeConfiancaTempoTotal1;
    }
    
    //verifica se um valor esta no intervalo de confianca de T1
    bool intervaloTempoTotal1(double valor)
    {
         if((valor>getPrimeiroMomentoT1()-getIntervaloDeConfiancaTempoTotal1())&&
            (valor<getPrimeiroMomentoT1()+getIntervaloDeConfiancaTempoTotal1()))
         {
             return true;
         }
         else
         {
             return false;
         }
    }
    
    //define o intervalo de confianca de T2
    void setIntervaloDeConfiancaTempoTotal2(int numeroDeRodadas)
	{
          setVarianciaTempoTotal2();
          varianciaTempoTotal2 /= numeroDeRodadas - 1;
          
          intervaloDeConfiancaTempoTotal2 = INTERVALODECONFIANCA95 * 
                                             (sqrt(varianciaTempoTotal2)/sqrt(numeroDeRodadas));
    }
    
    double getIntervaloDeConfiancaTempoTotal2()
    {
          return intervaloDeConfiancaTempoTotal2;
    }
    
    //verifica se um valor esta no intervalo de confianca de T2
    bool intervaloTempoTotal2(double valor)
    {
         if((valor>getTempoTotal2Medio()-getIntervaloDeConfiancaTempoTotal2())&&
            (valor<getTempoTotal2Medio()+getIntervaloDeConfiancaTempoTotal2()))
         {
             return true;
         }
         else
         {
             return false;
         }
    }
    //*/
};
#endif
